import com.google.maps.LatLng;
import com.google.maps.LatLngBounds;
import com.google.maps.Map;
import com.google.maps.MapEvent;
import com.google.maps.MapType;
import com.google.maps.controls.MapTypeControl;
import com.google.maps.controls.ZoomControl;
import com.google.maps.overlays.Marker;

import flare.animate.Tween;

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.text.TextFormat;

import mx.collections.ArrayList;
import mx.core.UIComponent;

// GLOBAL VARIABLES
private var isFullRes:Boolean = false;

private var g_picList:Array = new Array();	// the list of the pictures for the day
private var g_currPage:int = 1;	// current page of pictures
private var g_totalPics:int = 0;	// total number of pictures, seeded w/ database value
private var g_totalVideos:int = 0;	// total number of videos, seeded w/ database value
private var g_hasBlog:Boolean = false; // flag for whether there is a blog entry for the day
private var g_picturesHeight:int = Common.getPicturesHeight();
private var g_picturesWidth:int = Common.getPicturesWidth();
private var g_picturesFullHeight:int = Common.getPicturesFullHeight();

// youtube video variables
Security.allowDomain("www.youtube.com");
private var youtubeLoader:Loader = new Loader();
private var youtubePlayer:Object;

// needed to work within mxml
private var base:UIComponent = new UIComponent();

/**
 * Draws the locations of the current day's photos on Google Maps
 */
private function onMapReady(event:Event):void {
	map.x = Common.LOCATION_X;
	map.y = Common.LOCATION_Y;
	map.width = Common.LOCATION_WIDTH;
	map.height = Common.LOCATION_HEIGHT;
	map.addControl(new ZoomControl());
	map.addControl(new MapTypeControl());
	
	var latLong:LatLng;
	var lat:Number, long:Number;
	var centerLat:Number = 0;
	var centerLong:Number = 0;
	var marker:Marker;
	var bounds:LatLngBounds = new LatLngBounds();
	for(var i:int = 0; i < g_picList.length; i++) {
		lat = g_picList[i].getLatitude();
		long = g_picList[i].getLongitude();
		
		// add the new marker to the map
		latLong = new LatLng(lat, long); 
		map.addOverlay(new Marker(latLong));
		
		// expand the bounds of the current range
		bounds.extend(latLong);
		
		// for calculating the center of the images
		centerLat += lat;
		centerLong += long;
	}
	centerLat = centerLat / g_totalPics;
	centerLong = centerLong / g_totalPics;
	
	map.setCenter(new LatLng(centerLat, centerLong));
	map.setMapType(MapType.NORMAL_MAP_TYPE);
	map.setZoom(map.getBoundsZoomLevel(bounds)); // zoom level determined by the range of the points
}

/** 
 * Creates the entire webpage
 */
public function initWebpage():void {
	// retrieves data from database and draws data dependent parts of site
	getDatabaseVariables();
	
	displayButtons();
	
	// everything is built with "base," so make sure to add it to the Flash!
	this.addChild(base);
	
	// set the mouse interactions
	initMouse();
	
	// DEV ONLY: draw a border so we can see where the end of the flash is
	//	drawBorder();
}

/**
 * Pulls necessary variables from the database
 */
private function getDatabaseVariables():void {
	var loader:URLLoader = new URLLoader();
	loader.addEventListener(Event.COMPLETE, parseXMLAndDrawAll); 
	loader.load(new URLRequest(Common.XML_FILE));
}

/**
 * 1) Parse the XML after it has finished loading
 * 2) Draw the elements of the site that depend on database variables
 */
private function parseXMLAndDrawAll(event:Event):void {
	var xml:XML = new XML(event.target.data);
	
	g_totalPics = xml.total;
	g_totalVideos = 1;	// TODO
	g_hasBlog = false;	//TODO
	
	// add the photos to an array
	var currPhoto:XML;
	for(var i:int = 0; i < g_totalPics; i++) {
		currPhoto = xml.photo[i];
		g_picList[i] = new Photo(currPhoto.@id, currPhoto.@time_captured, currPhoto.@latitude,
			currPhoto.@longitude, currPhoto.@altitude, currPhoto.@url);
	}
	
	// if there are no videos or blogs to display,
	// extend the picture frame to take up the otherwise
	// unused space
	if(g_totalVideos == 0 && !g_hasBlog) {
		g_picturesHeight = 2 * Common.getPicturesHeight();
		g_picturesFullHeight = g_picturesHeight + 30;
	}
	
	// Draw database dependent site portions
	displayTitle();
	displayDate();
	if(g_totalPics > 0) {
		displayPictures(1, g_totalPics); // draw the framework for picture display
		displayWeather();
	}
	if(g_totalVideos > 0) {
		displayVideos();
	}
	if(g_hasBlog) {
		displayBlog();
	}
}

// ******** MOUSE INTERACTIONS **********/
private function initMouse():void {
	this.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
	this.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
	this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
	//			this.addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
}

// ******** TOP OF SCREEN ********/
private function displayTitle():void {
	// wrapper
	var border:Sprite = new Sprite();
	border.x = Common.TITLE_X;
	border.y = Common.TITLE_Y;
	//			border.graphics.lineStyle(5, 0xFF0000);
	border.graphics.drawRect(0, 0, Common.TITLE_WIDTH, Common.TITLE_HEIGHT);
	
	var username:String = "Greg";	// TODO php call
	var location:String = "Japan";	// TODO php call
	var textStyle:TextFormat = new TextFormat();
	textStyle.font = "Calibri";
	textStyle.bold = true;
	textStyle.size = 40;
	textStyle.align = "center";
	
	var titleText:TextField = new TextField();
	titleText.width = Common.TITLE_WIDTH;	
	titleText.height = Common.TITLE_HEIGHT;
	titleText.text = username + "\'s trip to " + location;
	titleText.setTextFormat(textStyle);
	border.addChild(titleText);
	
	base.addChild(border);
}

private function displayDate():void {
	// wrapper
	var border:Sprite = new Sprite();
	border.x = Common.DATE_X;
	border.y = Common.DATE_Y;
	//border.graphics.lineStyle(5, 0xFF0000);
	//	border.graphics.drawRect(0, 0, Common.DATE_WIDTH, Common.DATE_HEIGHT);
	base.addChild(border);
	
	// date text
	var date:String = "June 24, 2009";	// TODO php call
	var textStyle:TextFormat = new TextFormat();
	textStyle.font = "Calibri";
	textStyle.bold = true;
	textStyle.size = 30;
	textStyle.align = "left";
	
	var myText:TextField = new TextField();
	myText.width = Common.DATE_WIDTH;	
	myText.height = Common.DATE_HEIGHT;
	myText.text = date;
	myText.setTextFormat(textStyle);
	myText.x = Common.DATE_WIDTH/2 - myText.textWidth/2;
	myText.y = Common.DATE_HEIGHT/2 - myText.textHeight/2;
	border.addChild(myText);
	
	// calendar button
	var calendar:Sprite = new Sprite();
	calendar.x = Common.CALENDAR_X;
	calendar.y = Common.CALENDAR_Y;
	calendar.graphics.beginFill(0x000000, 1.0);
	calendar.graphics.drawRect(0, 0, Common.CALENDAR_WIDTH, Common.CALENDAR_HEIGHT);
	calendar.buttonMode = true;
	base.addChild(calendar);
}

// ******** LEFT 2/3rds OF SCREEN ********/
public function displayPictures(currPage:int, totalPics:int):void {
	// draw the wrapper that contains all of the picture elements
	var border:Sprite = new Sprite();
	border.x = Common.PICTURES_X;
	border.y = Common.PICTURES_Y;
	//			border.graphics.lineStyle(5, 0xFF0000);
	border.graphics.drawRect(0, 0, g_picturesWidth, g_picturesFullHeight);
	border.name = Common.PICTURE_WRAPPER;
	base.addChild(border);
	
	// draw the picture thumbnails
	var pic:Sprite;
	var cols:int = g_picturesWidth / Common.THUMB_WIDTH;
	var colSpace:int = (g_picturesWidth - (cols * Common.THUMB_WIDTH)) / (cols - 1);
	var rows:int = g_picturesHeight / Common.THUMB_HEIGHT;
	var rowSpace:int = (g_picturesHeight - (rows * Common.THUMB_HEIGHT)) / (rows - 1);
	
	var tempPicIndex:int = 1;
	var currPicIndex:int;
	var numPicsPerPage:int = cols * rows;
	var lastRowHeight:int = Common.THUMB_HEIGHT;	// the y-coordinate of the last row
	for(var y:int = 0; y <= g_picturesHeight - Common.THUMB_HEIGHT; y += Common.THUMB_HEIGHT + rowSpace) {
		for (var x:int = 0; x <= g_picturesWidth - Common.THUMB_WIDTH; x += Common.THUMB_WIDTH + colSpace) {
			currPicIndex = (currPage-1) * numPicsPerPage + tempPicIndex - 1;
			
			// can't draw more than the total number of pics
			if (currPicIndex < totalPics) {
				// update the location of last row
				lastRowHeight = y + Common.THUMB_HEIGHT;
				
				// draw the pictures 
				pic = new Sprite();
				pic.x = x;
				pic.y = y;
				
				// load images from server
				var urlRequest:URLRequest = new URLRequest(g_picList[currPicIndex].getUrl());
				var loader:Loader = new Loader();
				loader.load(urlRequest);
				loader.contentLoaderInfo.addEventListener(Event.INIT, imageLoadComplete);
				
				pic.addChild(loader);
				
				// picture characteristics				
				pic.name = Common.PICTURE;
				pic.buttonMode = true;
				
				border.addChild(pic);
				
				tempPicIndex++;
			} else {
				break;
			}
		}
	}
	
	// draw the "view all pictures" link
	border.addChild(drawViewAllLink(lastRowHeight));
	
	// draw the picture navigation buttons
	if (currPage != 1) { // the first page doesn't have a back button
		border.addChild(drawPicBackButton());
	}
	
	// the last page doesn't have forward button
	if (currPage * numPicsPerPage < totalPics) {
		border.addChild(drawPicForwardButton());
	}
}

/**
 * Adjusts properties of the Loader (which holds our picture)
 * after the loading is complete
 */
private function imageLoadComplete(event:Event):void {
	var loader:Loader = Loader(event.target.loader);
	//	loader.width = Common.THUMB_WIDTH;
	//	loader.height = Common.THUMB_HEIGHT;
	var picWidth:Number = loader.width;
	var picHeight:Number = loader.height;
	var scaler:Number;
	
	// vertically oriented pictures
	if (picHeight > picWidth) {
		scaler = picHeight / Common.THUMB_HEIGHT;
	} else { // horizontally oriented pictures
		scaler = picWidth / Common.THUMB_WIDTH;
	}
	
	// shrink the picture to fit as a thumbnail
	loader.height = picHeight / scaler;
	loader.width = picWidth / scaler;
	loader.x = Common.THUMB_WIDTH/2 - loader.width/2;
	loader.y = Common.THUMB_HEIGHT/2 - loader.height/2;
}

private function drawViewAllLink(lastRowHeight:int):Sprite {
	var border:Sprite = new Sprite();
	
	// text formatting
	var textStyle:TextFormat = new TextFormat();
	textStyle.font = "Calibri";
	textStyle.size = 20;
	textStyle.align = "right";
	textStyle.underline = true;
	textStyle.color = 0x0000FF;
	
	// actual text
	var myText:TextField = new TextField();
	myText.width = g_picturesWidth/2;	
	myText.height = Common.THUMB_HEIGHT;
	myText.text = "View all pictures (" + g_totalPics + " total)";
	myText.x = g_picturesWidth/2;
	myText.y = lastRowHeight + 5;
	myText.setTextFormat(textStyle);
	border.addChild(myText);
	
	// add a button overlay for mouse interaction
	var buttonOverlay:Sprite = new Sprite();
	buttonOverlay.x = myText.x;
	buttonOverlay.y = myText.y;
	buttonOverlay.graphics.beginFill(0xFF0000, 0.0);
	buttonOverlay.graphics.drawRect(0, 0, myText.width, myText.textHeight);
	buttonOverlay.name = Common.VIEW_ALL_PICS;
	buttonOverlay.buttonMode = true;
	border.addChild(buttonOverlay);
	
	return border;
}

private function drawPicBackButton():Sprite {
	var button:Sprite = new Sprite();
	
	// draw rectangle outline
	button.x = -Common.PIC_BUTTON_WIDTH/2;
	button.y = g_picturesHeight/2 - Common.PIC_BUTTON_HEIGHT/2;
	button.graphics.beginFill(0x000000, 0.2);
	button.graphics.drawRoundRect(0, 0, Common.PIC_BUTTON_WIDTH, Common.PIC_BUTTON_HEIGHT, Common.PIC_BUTTON_WIDTH/2);
	button.graphics.endFill();
	button.graphics.lineStyle(10, 0x000000, 1.0);
	button.graphics.moveTo(Common.PIC_BUTTON_WIDTH - Common.PIC_BUTTON_BUFFER, Common.PIC_BUTTON_BUFFER);
	button.graphics.lineTo(Common.PIC_BUTTON_BUFFER, Common.PIC_BUTTON_HEIGHT/2);
	button.graphics.lineTo(Common.PIC_BUTTON_WIDTH - Common.PIC_BUTTON_BUFFER, Common.PIC_BUTTON_HEIGHT - Common.PIC_BUTTON_BUFFER);
	
	// button metadata
	button.name = Common.PIC_BACK_BUTTON;
	button.buttonMode = true;
	return button;
}

private function drawPicForwardButton():Sprite {
	var button:Sprite = new Sprite();
	
	// draw rectangle outline
	button.x = g_picturesWidth - Common.PIC_BUTTON_WIDTH/2;
	button.y = g_picturesHeight/2 - Common.PIC_BUTTON_HEIGHT/2;
	button.graphics.beginFill(0x000000, 0.2);
	button.graphics.drawRoundRect(0, 0, Common.PIC_BUTTON_WIDTH, Common.PIC_BUTTON_HEIGHT, Common.PIC_BUTTON_WIDTH/2);
	button.graphics.endFill();
	button.graphics.lineStyle(10, 0x000000, 1.0);
	button.graphics.moveTo(Common.PIC_BUTTON_BUFFER, Common.PIC_BUTTON_BUFFER);
	button.graphics.lineTo(Common.PIC_BUTTON_WIDTH - Common.PIC_BUTTON_BUFFER, Common.PIC_BUTTON_HEIGHT/2);
	button.graphics.lineTo(Common.PIC_BUTTON_BUFFER, Common.PIC_BUTTON_HEIGHT - Common.PIC_BUTTON_BUFFER);
	
	//	// draw arrow shape
	//	button.graphics.beginFill(0x000000, 1.0);
	//	var buffer:Number = Common.PIC_BUTTON_WIDTH/5;
	
	//	var buffer2:Number = Common.PIC_BUTTON_WIDTH/5;
	//	var vertices:Vector.<Number> = Vector.<Number>([
	//		Common.PIC_BUTTON_WIDTH - buffer, Common.PIC_BUTTON_HEIGHT/2,
	//		buffer2, Common.PIC_BUTTON_HEIGHT - buffer2,
	//		buffer2, buffer2
	//	]);
	//	var indices:Vector.<int> = Vector.<int>([0, 1, 2]);
	//	button.graphics.drawTriangles(vertices, indices);
	//	button.graphics.endFill();
	
	// button metadata
	button.name = Common.PIC_FORWARD_BUTTON;
	button.buttonMode = true;
	return button;
}

/** 
 * navigates between different pages of pictures
 */
private function redrawPictures(currPage:int):void {
	// remove the current page of pictures
	base.removeChild(base.getChildByName(Common.PICTURE_WRAPPER));
	
	// draw new page of pictures
	displayPictures(currPage, g_totalPics);
}

private function displayVideos():void {
	var border:Sprite = new Sprite();
	border.x = Common.VIDEO_X;
	border.y = Common.VIDEO_Y;
	//	border.graphics.lineStyle(5, 0xFF0000);
	//	border.graphics.drawRect(0, 0, Common.VIDEO_WIDTH, Common.VIDEO_HEIGHT);
	
	// The player SWF file on www.youtube.com needs to communicate with your host
	// SWF file. Your code must call Security.allowDomain() to allow this
	// communication.
	//	Security.allowDomain("www.youtube.com");
	
	youtubeLoader.load(new URLRequest("http://www.youtube.com/v/O4pPQVLwPB8?version=3"));
	youtubeLoader.contentLoaderInfo.addEventListener(Event.INIT, onLoaderInit);
	
	border.addChild(youtubeLoader);	
	base.addChild(border);
}

private function onLoaderInit(event:Event):void {
	youtubeLoader.content.addEventListener("onReady", onPlayerReady);
}

private function onPlayerReady(event:Event):void {
	// Event.data contains the event parameter, which is the Player API ID 
	trace("player ready:", Object(event).data);
	
	// Once this event has been dispatched by the player, we can use
	// cueVideoById, loadVideoById, cueVideoByUrl and loadVideoByUrl
	// to load a particular YouTube video.
	// This will hold the API player instance once it is initialized.
	youtubePlayer = youtubeLoader.content;
	
	// Set appropriate player dimensions for your application
	youtubePlayer.setSize(Common.VIDEO_WIDTH, Common.VIDEO_HEIGHT);
	youtubePlayer.setPlaybackQuality("small");
}

private function displayBlog():void {
	var border:Sprite = new Sprite();
	border.x = Common.BLOG_X;
	border.y = Common.BLOG_Y;
	border.graphics.lineStyle(5, 0xFF0000);
	border.graphics.drawRect(0, 0, Common.BLOG_WIDTH, Common.BLOG_HEIGHT);
	base.addChild(border);
}

// ******** RIGHT 1/3rd OF SCREEN ********/
private function displayWeather():void {
	var border:Sprite = new Sprite();
	border.x = Common.WEATHER_X;
	border.y = Common.WEATHER_Y;
	//	border.graphics.lineStyle(5, 0xFF0000);
	border.graphics.drawRect(0, 0, Common.WEATHER_WIDTH, Common.WEATHER_HEIGHT);
	
	// TODO draw the appropriate weather icon
	var urlRequest:URLRequest = new URLRequest(Common.STORM);
	var loader:Loader = new Loader();
	loader.load(urlRequest);
	loader.contentLoaderInfo.addEventListener(Event.INIT, weatherImageLoad);
	
	border.addChild(loader);
	base.addChild(border);
}

private function weatherImageLoad(event:Event):void {
	var loader:Loader = Loader(event.target.loader);
	loader.height = Common.WEATHER_HEIGHT;
	loader.width = loader.height;
	
	loader.x = Common.WEATHER_WIDTH/2 - loader.width/2;
	//	loader.y = Common.WEATHER_HEIGHT/2 - loader.height/2;
}

// ******** NAVIGATION BUTTONS ********/
private function displayButtons():void {
	displayLeftButton();
	displayRightButton();
}

private function displayLeftButton():void {
	// button
	var border:Sprite = new Sprite();
	border.x = Common.LBUTTON_X;
	border.y = Common.LBUTTON_Y;
	border.graphics.lineStyle(3, Common.BUTTON_OUTLINE);
	border.graphics.beginFill(Common.BUTTON_FILL, 1.0);
	border.graphics.drawRoundRect(0, 0, Common.BUTTON_WIDTH, Common.BUTTON_HEIGHT, Common.BUTTON_HEIGHT);
	base.addChild(border);
	
	// button text
	var textStyle:TextFormat = new TextFormat();
	textStyle.font = "Calibri";
	textStyle.size = 24;
	textStyle.align = "center";
	textStyle.color = 0xFFFFFF;
	
	var myText:TextField = new TextField();
	myText.width = Common.BUTTON_WIDTH;	
	myText.height = Common.BUTTON_HEIGHT;
	myText.y = 8;
	myText.text = "<< Previous travel day";
	myText.setTextFormat(textStyle);
	border.addChild(myText);
	
	// top layer sprite for mouse interaction
	var button:Sprite = new Sprite();
	button.graphics.beginFill(Common.BUTTON_FILL, 0.0);
	button.graphics.drawRect(0, 0, Common.BUTTON_WIDTH, Common.BUTTON_HEIGHT);
	button.buttonMode = true;
	border.addChild(button);
}

private function displayRightButton():void {
	var border:Sprite = new Sprite();
	border.x = Common.RBUTTON_X;
	border.y = Common.RBUTTON_Y;
	border.graphics.lineStyle(3, Common.BUTTON_OUTLINE);
	border.graphics.beginFill(Common.BUTTON_FILL, 1.0);
	border.graphics.drawRoundRect(0, 0, Common.BUTTON_WIDTH, Common.BUTTON_HEIGHT, Common.BUTTON_HEIGHT);
	base.addChild(border);
	
	// button text
	var textStyle:TextFormat = new TextFormat();
	textStyle.font = "Calibri";
	textStyle.size = 24;
	textStyle.align = "center";
	textStyle.color = 0xFFFFFF;
	
	var myText:TextField = new TextField();
	myText.width = Common.BUTTON_WIDTH;	
	myText.height = Common.BUTTON_HEIGHT;
	myText.y = 8;
	myText.text = "Next travel day >>";
	myText.setTextFormat(textStyle);
	border.addChild(myText);
	
	// top layer sprite for mouse interaction
	var button:Sprite = new Sprite();
	button.graphics.beginFill(Common.BUTTON_FILL, 0.0);
	button.graphics.drawRect(0, 0, Common.BUTTON_WIDTH, Common.BUTTON_HEIGHT);
	button.buttonMode = true;
	border.addChild(button);
}

/**
 *  DEV ONLY: draw a border so we can see where the end of the flash is
 */
private function drawBorder():void {
	var border:Sprite = new Sprite();
	border.graphics.lineStyle(5, 0x0000AA);
	border.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
	base.addChild(border);
}

// *****************************************************
// ******************** MOUSE STUFF ********************
// *****************************************************
public function onMouseOver(event:MouseEvent):void {
	var mouseTarget:Object = event.target;
	
	if(mouseTarget is Sprite) {
		if(mouseTarget.name == Common.PICTURE) {
			//toggleFullRes(mouseTarget as Sprite);
		}
		
	}
}

public function onMouseOut(event:MouseEvent):void {
}

public function onMouseUp(event:MouseEvent):void {
	var mouseTarget:Object = event.target;
	
	trace("click");
	
	if(mouseTarget is Sprite) {
		if(mouseTarget.name == Common.PIC_FORWARD_BUTTON) {
			g_currPage++;
			redrawPictures(g_currPage);
		} else if(mouseTarget.name == Common.PIC_BACK_BUTTON) {
			g_currPage--;
			redrawPictures(g_currPage);
		}
	}
}

public function toggleFullRes(pic:Sprite):void {
	//			if(!isFullRes) {
	//				isFullRes = true;
	//				
	//				// increase the size of the thumbnail
	//				var fullResTween:Tween = new Tween(pic, 0.3, 
	//					{
	//						x: 0,
	//						y: 0,
	//						width: 800,
	//						height: 600
	//					}
	//				);
	//				fullResTween.play();	// zoom in
	//			} else {
	//				isFullRes = false;
	//			}
}

